﻿using System.Threading;
using System.Windows;
using Fluffy.Library.FileSources;
using Fluffy.Library.Utils;
using MonoTorrent;
using MonoTorrent.Client;
using MonoTorrent.Client.Encryption;
using MonoTorrent.Common;
using System;
using System.IO;
using System.Net;

namespace Fluffy.Torrent
{
	internal class TorrentDocumentModel : IDisposable
	{
		private readonly IFile _file;
		private readonly MonoTorrent.Common.Torrent _torrent;
		private readonly MagnetLink _magnet;
		private readonly ManualResetEvent _disposeFinishedEvent = new ManualResetEvent(true);

		public event Action<double, int> ProgressChanged;

		private bool _isDisposed;

		public TorrentDocumentModel(IFile file)
		{
			_file = file;
			if (_file is LinkFile) 
				_magnet = new MagnetLink(_file.FilePath);
			else 
				_torrent = MonoTorrent.Common.Torrent.Load(_file.FilePath);
		}

		public TorrentFile[] Files
		{
			get { return _torrent.Files; }
		}
		
		public string Name
		{
			get { return _torrent == null ? _magnet.Name : _torrent.Name; }
		}

		public string Comment
		{
			get { return _torrent == null ? string.Empty : _torrent.Comment; }
		}

		public string CreatedBy
		{
			get { return _torrent == null ? string.Empty : _torrent.CreatedBy; }
		}

		public string PublisherUrl
		{
			get { return _torrent == null ? string.Empty : _torrent.PublisherUrl; }
		}

		public string Publisher
		{
			get { return _torrent == null ? string.Empty : _torrent.Publisher; }
		}

		public string TorrentPath
		{
			get { return _torrent == null ? string.Empty : _torrent.TorrentPath; }
		}

		public string CreatedDate
		{
			get { return _torrent == null ? string.Empty : _torrent.CreationDate.ToLongDateString(); }
		}

		public long Size
		{
			get { return _torrent == null ? 0 : _torrent.Size; }
		}

		public void Load(string dir)
		{
			if (_isDisposed)
				throw new InvalidOperationException("This instance is disposed.");

			try
			{
				_disposeFinishedEvent.Reset();

				EngineSettings settings = new EngineSettings();
				settings.AllowedEncryption = EncryptionTypes.All;
				settings.PreferEncryption = true;
				settings.SavePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Torrents");

				using (ClientEngine engine = new ClientEngine(settings))
				{
					engine.ChangeListenEndpoint(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6969));

					using (TorrentManager manager = new TorrentManager(_torrent, dir, new TorrentSettings()))
					{
						engine.Register(manager);

						try
						{
							PiecePicker picker = new StandardPicker();
							picker = new PriorityPicker(picker);
							manager.ChangePicker(picker);

							manager.Start();

							try
							{
								while (!manager.Complete && !_isDisposed)
								{
									Thread.Sleep(1000);

									if (ProgressChanged != null)
										ProgressChanged(manager.Progress, manager.Monitor.DownloadSpeed);
								}
							}
							finally
							{
								manager.Stop();
								ThreadUtils.SleepWhile(() => manager.State != TorrentState.Stopped);
							}
						}
						finally
						{
							engine.Unregister(manager);
						}
					}
				}
			}
			finally
			{
				_disposeFinishedEvent.Set();
			}
		}

		public void Dispose()
		{
			_isDisposed = true;
			_disposeFinishedEvent.WaitOne();
		}
	}
}
